using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace SPGE.TextureEffects
{
    public class CustomTextureEffect : ITextureEffect
    {
        protected RenderTarget2D Data
        { get; private set; }

        public EnumTextureEffectCalculation TextureCalculation
        { get; private set; }

        protected Func<Color[], int, int, Color[]> Calculate
        { private get; set; }

        private bool Calculated
        { get; set; }

        private GameItem Target
        { get; set; }

        public virtual bool IsVisible
        { get { return true; } }

        private bool ForceCalculation
        { get; set; }

        public CustomTextureEffect(EnumTextureEffectCalculation textureCalculation, Func<Color[], int, int, Color[]> calculate)
        {
            TextureCalculation = textureCalculation;
            Calculate = calculate;
            Calculated = false;
        }

        protected CustomTextureEffect(EnumTextureEffectCalculation textureCalculation)
        {
            TextureCalculation = textureCalculation;
            Calculated = false;
        }

        public void GameItemLoaded(IGameItem input)
        {
            var gameItem = input as GameItem;

            if (gameItem == null)
                return;

            if (Data == null)
                Data = new RenderTarget2D(GameContainer.Device, gameItem.SourceRectangle.Width, gameItem.SourceRectangle.Height, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PlatformContents);

            if (TextureCalculation == EnumTextureEffectCalculation.Eager)
            {
                CalculateData(gameItem);
                ForceCalculation = false;
            }
        }

        public Texture2D ApplyEffect(GameItem input)
        {
            if (Data == null)
                Data = new RenderTarget2D(GameContainer.Device, input.SourceRectangle.Width, input.SourceRectangle.Height, true, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PlatformContents);

            if (!ForceCalculation && Calculated && TextureCalculation != EnumTextureEffectCalculation.PerFrame)
                return Data;
            else
            {
                CalculateData(input);
                ForceCalculation = false;
            }

            return Data;
        }

        public void ForceCalculate()
        {
            ForceCalculation = true;
        }

        private void CalculateData(GameItem input)
        {
            Color[] data = new Color[input.SourceRectangle.Width * input.SourceRectangle.Height];
            input.Texture.GetData<Color>(0, input.SourceRectangle, data, 0, data.Length);

            Data.SetData<Color>(Calculate(data, input.SourceRectangle.Width, input.SourceRectangle.Height));

            Calculated = true;
        }

        #region IDisposable
        public void Dispose()
        {
            Dispose(true);
        }

        ~CustomTextureEffect()
        {
            Dispose(false);
        }

        private void Dispose(bool disposing)
        {
            if (!disposing)
            {
                Data.Dispose();
                Data = null;
            }

            Calculated = false;
        }
        #endregion
    }
}
